import socket
from datetime import datetime


class HTTPRequest(object):
    def __init__(self, conn, method, url, headers):
        self._conn = conn
        self.method = method
        self.url = url
        self.headers = headers

    def start_response(self, code, status):
        self._conn.send("HTTP/1.0 %s %s\r\n" % (code, status))

    def send_header(self, key, value):
        self._conn.send("%s: %s\r\n" % (key, value))

    def send_body(self, data):
        self._conn.send(data)

    def response(self, data, code=200, status='OK', **headers):
        self.start_response(code, status)

        headers.setdefault('server', 'low_level_stuff/wiz')  # should not be there?
        headers.setdefault('date', datetime.now().ctime())

        if 'content_type' not in headers:
            headers['content_type'] = 'text/plain'

        if 'content_length' not in headers:
            headers['content_length'] = len(data)

        for key, value in sorted(headers.iteritems()):
            self.send_header('-'.join(part.title() for part in key.split('_')), value)

        self._conn.send('\r\n')  # finish headers, start body

        self.send_body(data)

class HTTPServer(object):
    def __init__(self, port, host='127.0.0.1'):
        self.port = port
        self.host = host
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.handlers = []

    def listen(self):
        self.socket.bind((self.host, self.port))
        self.socket.listen(10)
        while True:
            conn, addr = self.socket.accept()
            self.on_connect(conn, addr)

    def on_connect(self, conn, addr):
        data = conn.recv(1024).split('\r\n')
        method, url, proto = data[0].split(' ', 2)

        headers = {}
        for line in data[1:]:
            if not line:
                break
            key, value = line.split(': ', 1)
            headers[key.upper()] = value

        self.on_request(HTTPRequest(conn, method, url, headers))
        conn.close()

    def on_request(self, request):
        for pattern, handler in self.handlers:
            if pattern(request):
                return handler(request)

        request.response('Not Found', 404, 'Not Found')

    def register(self, pattern, handler):
        self.handlers.append((pattern, handler))

if __name__ == '__main__':
    from sys import argv

    server = HTTPServer(int(sys.argv[1]) if len(argv) > 1 else 8001)
    server.register(lambda req: req.url.startswith('/lol/'), lambda req: req.response('ok'))
    server.register(lambda req: True, lambda req: req.response('Hel<a href="/lol">lol</lol>!', content_type='text/html'))
    server.listen()
